<?php

declare (strict_types = 1);

namespace app\tpwork;

use app\tpwork\helps\MsgEnum;
use app\tpwork\helps\Tool;
use own\exception\TipsException;
use own\helps\RespCode;
use own\helps\OwnDecrypt;
use think\Exception;
use think\worker\Server;
use TypeError;
use Workerman\Worker;

/**
 * 客服聊天室
 */
class Websocket extends Server
{
    protected $socket = 'websocket://0.0.0.0:9521';
    
    protected $online = [];

    public function onWorkerStart()
    {
        $pushWorker = new Worker('text://0.0.0.0:9522');
        $pushWorker->onMessage = function ($connection, $buffer) {
            $connection->send(Tool::success());
            try {
                $data = json_decode($buffer, true);
                if(isset($data['uids'])) {
                    foreach($data['uids'] as $uid) {
                        if(isset($this->online[$uid])) {
                            $o['uid'] = $uid;
                            $o['code'] = MsgEnum::NOTICE;
                            $this->online[$uid]->send(Tool::success(['uid'=>$uid], MsgEnum::NOTICE));
                        }
                    }
                }
            } catch (Exception $e) {
                echo "ERROR: {$e->getMessage()}\n";
            }
        };
        $pushWorker->listen();
    }

    public function onConnect($connection)
    {
        $connection->send(Tool::success('连接成功'));
    }

    public function onMessage($connection, $data)
    {
        try {
            $msg = json_decode($data, true);
            // 身份验证
            self::authentication((int) $msg['uid'], $msg['sign']);
            if (!isset($connection->uid) && $msg['uid']) {
                $connection->uid = $msg['uid'];
                $this->online[$connection->uid] = $connection;
            }
            $connection->send(Tool::success());
        } catch (TipsException $e) {
            $connection->send(Tool::error($e->getMessage(), $e->getCode()));
        } catch (TypeError $e) {
            $connection->send(Tool::error($e->getMessage()));
        } catch (Exception $e) {
            $connection->send(Tool::error($e->getMessage(), RespCode::ERROR));
        }
    }

    public function onClose($connection)
    {
        if (isset($connection->uid)) {
            unset($this->online[$connection->uid]);
        }
    }
    /**
     * 身份验证
     * @param integer $uid
     * @param string $mds
     */
    public static function authentication(int $uid, string $mds): void 
    {
        $data = (new OwnDecrypt())->decrypt($mds);
        if(!$data) {
            tips('身份验证错误', RespCode::NOT_LOGIN);
        } else {
            $data = json_decode($data, true);
        }
        if($uid != $data['id']) {
            tips('身份验证错误', RespCode::NOT_LOGIN);
        }
        if($data['time'] < time()) {
            tips('签名过期', RespCode::NOT_LOGIN);
        }
    }

}
